
// FillDiskPublicDlg.cpp : implementation file
//

/*
*****************************************************************************
*                                                                           *
*   Program functions:                                                      *
*                                                                           *
*   Fill hard disk(s) by dummy files                                        *
*                                                                           *
*   Author: Allan Qiu                                                       *
*                                                                           *
*   Version: 1.3.0.1                                                        *
*                                                                           *
*   Latest update: 2012-10-11 by Allan Qiu                                  *
*                                                                           *
*****************************************************************************
*/

#include "stdafx.h"
#include "FillDiskPublic.h"
#include "FillDiskPublicDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

UINT FillDiskFAT32Thread(LPVOID pParam)
{
	CFillDiskPublicDlg * pFillDiskPublicDlg = (CFillDiskPublicDlg *)pParam;

	if (NULL == pFillDiskPublicDlg)
	{
		return -1;
	}

	__int64 iFileLength	= pFillDiskPublicDlg->GetFileLength();
	wchar_t wchDriveLetter[4] = _T(" :\\");
	wchDriveLetter[0] = pFillDiskPublicDlg->GetCurrentDisk();

	pFillDiskPublicDlg->CreateFillFileFAT32(wchDriveLetter, iFileLength);

	int	iFAT32DiskCount;
	int	iAllDiskCount;

	iFAT32DiskCount = pFillDiskPublicDlg->GetFAT32DiskCount();
	iAllDiskCount = pFillDiskPublicDlg->GetAllDiskCount();

	iFAT32DiskCount--;
	iAllDiskCount--;

	pFillDiskPublicDlg->SetFAT32DiskCount(iFAT32DiskCount);
	pFillDiskPublicDlg->SetAllDiskCount(iAllDiskCount);

	if ((0 == iFAT32DiskCount) && (0 == iAllDiskCount))
	{
		pFillDiskPublicDlg->AfterAllDiskFillFinished();
	}

	return 0;
}

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	virtual BOOL OnInitDialog();
	
	DECLARE_MESSAGE_MAP()

public:
	void GetBasicInfo();
	void GetVersion();
	void GetAuthor();
	void GetEMail();

	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BOOL CAboutDlg::OnInitDialog()
{
	GetBasicInfo();
	return TRUE;
}

void CAboutDlg::GetBasicInfo()
{
	GetVersion();
	GetAuthor();
	GetEMail();
}

void CAboutDlg::GetVersion()
{
	wchar_t wchFilePath[MAX_PATH];
	GetModuleFileName(NULL, wchFilePath, sizeof(wchFilePath));

	DWORD dwVerInfoSize = 0; 
	DWORD dwVerHnd; 
	dwVerInfoSize = GetFileVersionInfoSize(wchFilePath, &dwVerHnd); 
	if (dwVerInfoSize)
	{
		CString strVersion; 

		HANDLE hMem;
		hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
		VERIFY(NULL != hMem);

		LPVOID lpvMem;
		lpvMem = GlobalLock(hMem);
		VERIFY(NULL != lpvMem );
		GetFileVersionInfo(wchFilePath, 0, sizeof(wchFilePath), lpvMem);

		unsigned int uInfoSize = 0;
		VS_FIXEDFILEINFO * pFileInfo;
		VerQueryValue(lpvMem, (LPTSTR)_T("\\"), (void**)&pFileInfo, &uInfoSize); 

		WORD nProdVersion[4]; 
		// Product version from the FILEVERSION of the version info resource
		nProdVersion[0] = HIWORD(pFileInfo->dwProductVersionMS);   
		nProdVersion[1] = LOWORD(pFileInfo->dwProductVersionMS); 
		nProdVersion[2] = HIWORD(pFileInfo->dwProductVersionLS); 
		nProdVersion[3] = LOWORD(pFileInfo->dwProductVersionLS);   

		strVersion.Format(_T( "%d.%d.%d.%d"),
			nProdVersion[0], nProdVersion[1], nProdVersion[2], nProdVersion[3]); 

		GlobalUnlock(hMem); 
		GlobalFree(hMem); 

		SetDlgItemText(IDC_STATIC_VERSION, strVersion);
	}
}

void CAboutDlg::GetAuthor()
{
	CString strAuthor;
	VERIFY(strAuthor.LoadString(IDS_AUTHOR));
	SetDlgItemText(IDC_STATIC_AUTHOR, strAuthor);
}

void CAboutDlg::GetEMail()
{
	CString strEmail;
	VERIFY(strEmail.LoadString(IDS_EMAIL_ADDRESS));
	SetDlgItemText(IDC_STATIC_EMAIL, strEmail);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CFillDiskPublicDlg dialog

CFillDiskPublicDlg::CFillDiskPublicDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CFillDiskPublicDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	m_bStartWithCmdArgs = false;

	m_wchCurrentDisk			= _T(' ');
	m_iAllDiskCount				= 0;
	m_iFAT32DiskCount			= 0;

	m_strFillFileName			= CString("FillDiskFile");
	m_strFillFileExtName		= CString(".tmp");

	m_strCurrentFillFileName	= CString("");
	VERIFY(m_strEMailAddress.LoadString(IDS_EMAIL_ADDRESS));

	m_strDefaultFreeSpace       = CString("10");

	m_iFileLength = -1;
	m_iFAT32FileMaxSize	= (__int64)1024 * (__int64)1024 * (__int64)1024;

	m_iDriverNameLength = GetLogicalDriveStrings(0, NULL);
	GetLogicalDriveStrings(m_iDriverNameLength, m_wchLogicalDrive);

	m_iFixedDriveCount = 0;
	for (int i = 0; i < INT_DISKCOUNT; i++)
	{
		wchar_t wchDriveLetter[4] = _T(" :\\");
		wchDriveLetter[0] = m_wchLogicalDrive[i * 4];
		if (DRIVE_FIXED == GetDriveType(wchDriveLetter))
		{
			m_WchDiskLetterList.AddTail(CString(wchDriveLetter));

			wchar_t wchDisk = 'A';
			wchDisk = wchDriveLetter[0] - 'A';
			m_nDiskIndexList.AddTail(wchDisk);

			m_iFixedDriveCount++;
		}
	}
}

CFillDiskPublicDlg::~CFillDiskPublicDlg()
{
	while (m_ListBoxList.GetCount() > 0)
	{
		CListBox * pObject = m_ListBoxList.GetTail();
		if (pObject)
		{
			delete pObject;
			pObject = NULL;
			m_ListBoxList.RemoveTail();
		}
	}

	while (m_ButtonList.GetCount() > 0)
	{
		CButton * pObject = m_ButtonList.GetTail();
		if (pObject)
		{
			delete pObject;
			pObject = NULL;
			m_ButtonList.RemoveTail();
		}
	}

	while (m_WinThreadList.GetCount() > 0)
	{
		CWinThread * pObject = m_WinThreadList.GetTail();
		if (pObject)
		{
			delete pObject;
			pObject = NULL;
			m_WinThreadList.RemoveTail();
		}
	}
}

void CFillDiskPublicDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CFillDiskPublicDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_CHECK_ALLDISK, &CFillDiskPublicDlg::OnBnClickedCheckAlldisk)
	ON_BN_CLICKED(IDC_BUTTON_REFRESHDISK, &CFillDiskPublicDlg::OnBnClickedButtonRefreshdisk)
	ON_BN_CLICKED(IDC_BUTTON_DELETEFILLFILE, &CFillDiskPublicDlg::OnBnClickedButtonDeletefillfile)
	ON_BN_CLICKED(IDC_BUTTON_FILLDISK_APPLY, &CFillDiskPublicDlg::OnBnClickedButtonFilldiskApply)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SHOWWINDOW()
	ON_BN_CLICKED(IDC_BUTTON_SENDEMAIL, &CFillDiskPublicDlg::OnBnClickedButtonSendEMail)
END_MESSAGE_MAP()


// CFillDiskPublicDlg message handlers

BOOL CFillDiskPublicDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.
	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	// Add "Help..." menu item to system menu.
	// IDM_HELPBOX must be in the system command range.
	ASSERT((IDM_HELPBOX & 0xFFF0) == IDM_HELPBOX);
	ASSERT(IDM_HELPBOX < 0xF000);

	// Add "Mail to author" menu item to system menu.
	// IDM_SENDMAIL must be in the system command range.
	ASSERT((IDM_SENDMAIL & 0xFFF0) == IDM_SENDMAIL);
	ASSERT(IDM_SENDMAIL < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}

		CString strHelpMenu;
		bNameValid = strHelpMenu.LoadString(IDS_HELPBOX);
		ASSERT(bNameValid);
		if (!strHelpMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_HELPBOX, strHelpMenu);
		}

		CString strMailMenu;
		bNameValid = strAboutMenu.LoadString(IDS_SENDMAIL);
		ASSERT(bNameValid);
		if (!strMailMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_STRING, IDM_SENDMAIL, strMailMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CFillDiskPublicDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		switch (nID & 0xFFF0)
		{
			case IDM_HELPBOX:
				ShowHelpWindow();
				break;
			case IDM_SENDMAIL:
				SendEMailToAuthor();
				break;
			default:
				CDialog::OnSysCommand(nID, lParam);
				break;
		}
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CFillDiskPublicDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CFillDiskPublicDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CFillDiskPublicDlg::OnBnClickedOk()
{
	FillDiskSpace();

	OnOK();
}

void CFillDiskPublicDlg::OnBnClickedCheckAlldisk()
{
	int iDiskAllCheck = ((CButton *)GetDlgItem(IDC_CHECK_ALLDISK))->GetCheck();
	for (int i = 0; i < m_iFixedDriveCount; i++)
	{
		POSITION pos;
		pos = m_WchDiskLetterList.FindIndex(i);
		wchar_t * wchDriveLetter = m_WchDiskLetterList.GetAt(pos).AllocSysString();
		pos = m_nDiskIndexList.FindIndex(i);
		int iDiskIndex = m_nDiskIndexList.GetAt(pos);

		CButton * pCheckDisk = (CButton *)GetDlgItem(IDC_CHECK_DISK0 + iDiskIndex);
		if (pCheckDisk)
		{
			if (BST_UNCHECKED == iDiskAllCheck) 
			{
				pCheckDisk->EnableWindow(TRUE);
			}

			if (BST_CHECKED == iDiskAllCheck)
			{
				pCheckDisk->EnableWindow(FALSE);
			}

			pCheckDisk->SetCheck(iDiskAllCheck);
		}
	}

	return;
}

void CFillDiskPublicDlg::OnBnClickedButtonRefreshdisk()
{
	RefreshDiskInfo();

	return;
}

void CFillDiskPublicDlg::OnBnClickedButtonDeletefillfile()
{
	DeleteAllFillFiles();
	RefreshDiskInfo();

	return;
}

void CFillDiskPublicDlg::OnBnClickedButtonFilldiskApply()
{
	FillDiskSpace();
	RefreshDiskInfo();
}

int CFillDiskPublicDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;

	return 0;
}

void CFillDiskPublicDlg::OnDestroy()
{
	CDialog::OnDestroy();
}

void CFillDiskPublicDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
	SetAllDiskCheckStatus();

	InitListCtrl();
	InitCheckCtrl();

	InitializeDefaultFreeSpace();

	ChangeDialogSize();

	CDialog::OnShowWindow(bShow, nStatus);

}

void CFillDiskPublicDlg::InitListCtrl(void)
{
	for (int i = 0; i < m_iFixedDriveCount; i++)
	{
		POSITION pos;
		pos = m_WchDiskLetterList.FindIndex(i);
		wchar_t * wchDriveLetter = m_WchDiskLetterList.GetAt(pos).AllocSysString();
		pos = m_nDiskIndexList.FindIndex(i);
		int iDiskIndex = m_nDiskIndexList.GetAt(pos);

		if (DRIVE_FIXED == GetDriveType(wchDriveLetter))
		{
			SetListInfo(wchDriveLetter, i, iDiskIndex);
		}
	}

	return;
}

void CFillDiskPublicDlg::SetListInfo(wchar_t * wchDriveLetter, int index, int iDiskIndex)
{
	CRect rectDiskList = CRect();
	CountDiskListBoxRect(rectDiskList, index);
	CreateDiskListBox(rectDiskList, IDC_LIST_DISK0 + iDiskIndex, wchDriveLetter);

	return;
}

void CFillDiskPublicDlg::CountDiskListBoxRect(CRect &rectDiskList, int index)
{
	int iRow = 0,			iColumn = 0;
	int iRowSpace = 20,		iColumnSpace = 20;
	int iHeight = 80,		iWidth = 200;
	int iLeft, iTop, iRight, iBottom;
	iLeft	= 20;
	iTop	= 85;
	iRight	= iLeft + iWidth;
	iBottom	= iTop + iHeight;

	iRow = index / 3;
	iColumn = index - (iRow * 3);

	rectDiskList.left = iLeft + iColumn * (iWidth + iColumnSpace);
	rectDiskList.top = iTop + iRow * (iHeight + iRowSpace);
	rectDiskList.right = iRight + iColumn * (iWidth + iColumnSpace);
	rectDiskList.bottom = iBottom + iRow * (iHeight + iRowSpace);

	return;
}

void CFillDiskPublicDlg::CreateDiskListBox(CRect rectDiskList, int iListBoxID, wchar_t * wchDriveLetter)
{
	CListBox * pListBox = new CListBox();
	pListBox->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, rectDiskList, 
		this, iListBoxID);
	VERIFY(pListBox);
	m_ListBoxList.AddTail(pListBox);

	pListBox->ModifyStyleEx(0, WS_EX_CLIENTEDGE);
	pListBox->SetFont(pListBox->GetParent()->GetFont());

	SetListStringInfo(pListBox, wchDriveLetter);

	return;
}

void CFillDiskPublicDlg::SetListString(CListBox * pListBox, wchar_t * wchDriveLetter)
{
	for (int i = pListBox->GetCount() - 1; i >= 0; i--)
	{
		pListBox->DeleteString(i);
	}

	SetListStringInfo(pListBox, wchDriveLetter);

	return;
}

void CFillDiskPublicDlg::SetListStringInfo(CListBox * pListBox, wchar_t * wchDriveLetter)
{
	wchar_t wchSysName[MAX_PATH];
	__int64 nFreeBytesAvailable;
	__int64 nTotalNumberOfBytes;
	__int64 nTotalNumberOfFreeBytes;
	wchar_t wchFreeAvailable[MAX_PATH] = _T("");
	wchar_t wchTotal[MAX_PATH] = _T("");
	wchar_t wchFreeTotal[MAX_PATH] = _T("");

	GetVolumeInformation(wchDriveLetter, NULL, NULL, NULL, NULL, NULL, wchSysName, sizeof(wchSysName));

	GetDiskFreeSpaceEx(wchDriveLetter, (PULARGE_INTEGER)&nFreeBytesAvailable, (PULARGE_INTEGER)&nTotalNumberOfBytes, (PULARGE_INTEGER)&nTotalNumberOfFreeBytes);
	_ui64tow_s((nFreeBytesAvailable / 1024 / 1024), wchFreeAvailable, 65, 10);
	_ui64tow_s((nTotalNumberOfBytes / 1024 / 1024), wchTotal, 65, 10);
	_ui64tow_s((nTotalNumberOfFreeBytes /1024 / 1024), wchFreeTotal, 65, 10);

	pListBox->AddString(CString("File system: ") + CString(wchSysName));
	pListBox->AddString(CString("Free space:  ") + CString(wchFreeAvailable) + CString(" MB"));
	pListBox->AddString(CString("Total space: ") + CString(wchTotal) + CString(" MB"));

	return;
}

void CFillDiskPublicDlg::InitCheckCtrl(void)
{
	for (int i = 0; i < m_iFixedDriveCount; i++)
	{
		POSITION pos;
		pos = m_WchDiskLetterList.FindIndex(i);
		wchar_t * wchDriveLetter = m_WchDiskLetterList.GetAt(pos).AllocSysString();
		pos = m_nDiskIndexList.FindIndex(i);
		int iDiskIndex = m_nDiskIndexList.GetAt(pos);

		SetCheckInfo(wchDriveLetter, i, iDiskIndex);
	}

	return;
}

void CFillDiskPublicDlg::SetCheckInfo(wchar_t * wchDriveLetter, int index, int iDiskIndex)
{
	CRect rectDiskCheck = CRect();
	CountDiskCheckRect(rectDiskCheck, index);
	CreateDiskCheckBox(rectDiskCheck, IDC_CHECK_DISK0 + iDiskIndex, wchDriveLetter);

	return;
}

void CFillDiskPublicDlg::CountDiskCheckRect(CRect &rectDiskCheck, int index)
{
	int iRow = 0,			iColumn = 0;
	int iRowSpace = 85,		iColumnSpace = 20;
	int iHeight = 15,		iWidth = 200;
	int iLeft, iTop, iRight, iBottom;
	iLeft	= 20;
	iTop	= 60;
	iRight	= iLeft + iWidth;
	iBottom	= iTop + iHeight;

	iRow = index / 3;
	iColumn = index - (iRow * 3);

	rectDiskCheck.left = iLeft + iColumn * (iWidth + iColumnSpace);
	rectDiskCheck.top = iTop + iRow * (iHeight + iRowSpace);
	rectDiskCheck.right = iRight + iColumn * (iWidth + iColumnSpace);
	rectDiskCheck.bottom = iBottom + iRow * (iHeight + iRowSpace);

	return;
}

void CFillDiskPublicDlg::CreateDiskCheckBox(CRect rectDiskCheck, int iCheckBoxID, wchar_t * wchDriveLetter)
{
	CString strCaption = CString("");
	VERIFY(strCaption.LoadString(iCheckBoxID));

	CButton * pCheckBox = new CButton();
	pCheckBox->Create(strCaption, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP, 
		rectDiskCheck, this, iCheckBoxID);
	VERIFY(pCheckBox);
	m_ButtonList.AddTail(pCheckBox);

	pCheckBox->SetFont(pCheckBox->GetParent()->GetFont());
	pCheckBox->SetCheck(BST_CHECKED);
	pCheckBox->EnableWindow(FALSE);

	return;
}

void CFillDiskPublicDlg::SetAllDiskCheckStatus(void)
{
	((CButton *)GetDlgItem(IDC_CHECK_ALLDISK))->SetCheck(BST_CHECKED);

	return;
}

void CFillDiskPublicDlg::InitializeDefaultFreeSpace(void)
{
	SetDlgItemText(IDC_EDIT_FILLNUMBER, m_strDefaultFreeSpace);
}

void CFillDiskPublicDlg::FillDiskSpace(void)
{
	m_iAllDiskCount = 0;
	m_iFAT32DiskCount = 0;

	CString strResidual = CString("");
	GetDlgItemText(IDC_EDIT_FILLNUMBER, strResidual);
	if (strResidual.Trim().IsEmpty())
	{
		AfxMessageBox(CString("Please input the free space number."));
		return;
	}

	__int64 iResidual = -1;
	iResidual = _wtoi64(strResidual.Trim());
	if (iResidual <= 0)
	{
		AfxMessageBox(CString("The free space number must > 0 ."));
		return;
	}

	SetFillButtonStatus(FALSE);

	if (((CButton *)GetDlgItem(IDC_CHECK_ALLDISK))->GetCheck())
	{
		FillAllDiskSpace(iResidual);
	}
	else
	{
		for (int i = 0; i < m_iFixedDriveCount; i++)
		{
			POSITION pos;
			pos = m_WchDiskLetterList.FindIndex(i);
			wchar_t * wchDriveLetter = m_WchDiskLetterList.GetAt(pos).AllocSysString();
			pos = m_nDiskIndexList.FindIndex(i);
			int iDiskIndex = m_nDiskIndexList.GetAt(pos);

			if (BST_CHECKED == ((CButton * )GetDlgItem(IDC_CHECK_DISK0 + iDiskIndex))->GetCheck())
			{
				FillOneDiskSpace(wchDriveLetter, iResidual);
			}
		}
	}

	if ((0 == m_iFAT32DiskCount) && (0 == m_iAllDiskCount))
	{
		AfterAllDiskFillFinished();
	}

	return;
}

void CFillDiskPublicDlg::FillAllDiskSpace(__int64 iResidual)
{
	for (int i = 0; i < m_iFixedDriveCount; i++)
	{
		POSITION pos = m_WchDiskLetterList.FindIndex(i);
		wchar_t * wchDriveLetter = m_WchDiskLetterList.GetAt(pos).AllocSysString();
		FillOneDiskSpace(wchDriveLetter, iResidual);
	}
}

void CFillDiskPublicDlg::FillOneDiskSpace(wchar_t * wchDriveLetter, __int64 iResidual)
{
	if (DRIVE_FIXED != GetDriveType(wchDriveLetter))
	{
		ShowMsg(_T("Disk ") + CString(wchDriveLetter[0]) + _T(" is not a FIXED driver."));
		ShowMsg(_T("So it will NOT be filled. "));
		ShowMsg(_T(" "));
		return;
	}

	wchar_t wchSysName[MAX_PATH] = _T("");
	GetVolumeInformation(wchDriveLetter, NULL, NULL, NULL, NULL, NULL, wchSysName, sizeof(wchSysName));
	__int64 nFreeBytesAvailable;
	__int64 nTotalNumberOfBytes;
	__int64 nTotalNumberOfFreeBytes;
	__int64 iFileLength = -1;

	GetDiskFreeSpaceEx(wchDriveLetter, (PULARGE_INTEGER)&nFreeBytesAvailable, (PULARGE_INTEGER)&nTotalNumberOfBytes, (PULARGE_INTEGER)&nTotalNumberOfFreeBytes);
	iFileLength = nTotalNumberOfFreeBytes - (iResidual * (__int64)1024 * (__int64)1024);

	if (0 < iFileLength)
	{
		m_iAllDiskCount++;
		if (CString("NTFS") == CString(wchSysName))
		{
			CreateFillFile(wchDriveLetter, iFileLength);
			m_iAllDiskCount--;
			AfterOneDiskFillFinished(wchDriveLetter);
		}

		if ((CString("FAT32") == CString(wchSysName))
			|| (CString("FAT") == CString(wchSysName)))
		{
			m_iFAT32DiskCount++;
			FillDiskSpaceFAT32(wchDriveLetter, iFileLength);
		}
	}
}

void CFillDiskPublicDlg::FillDiskSpaceFAT32(wchar_t * wchDriveLetter, __int64 iFileLength)
{
	ShowMsg(CString(wchDriveLetter) + CString(" is a FAT32 disk. "));
	ShowMsg(CString("Fill this disk by huage file need some time. "));
	ShowMsg(CString("Please wait..."));

	if (m_bStartWithCmdArgs)
	{
		CreateFillFileFAT32(wchDriveLetter, iFileLength);
	}
	else
	{
		m_iFileLength		= iFileLength;
		m_wchCurrentDisk	= wchDriveLetter[0];

		CWinThread * pSubWinThread = new CWinThread();
		VERIFY(pSubWinThread);
		m_WinThreadList.AddTail(pSubWinThread);

		pSubWinThread = AfxBeginThread(&FillDiskFAT32Thread, this);
	}
	return;
}

void CFillDiskPublicDlg::CreateFillFile(wchar_t * wchDriveLetter, __int64 iFileLength)
{
	CFile fillFile;
	int iCount = 0;
	char chCount[65];

	CString strFindFileName = CString("");
	strFindFileName  = CString(wchDriveLetter);
	strFindFileName += m_strFillFileName;
	strFindFileName += CString("*");
	strFindFileName += m_strFillFileExtName;

	CString strFileName = CString("");

	CFileFind finder;
	BOOL bFind = finder.FindFile(strFindFileName);
	while (bFind)
	{
		bFind = finder.FindNextFile();
		iCount++;
	}

	_itoa_s(iCount, chCount, 65, 10);
	strFileName  = CString(wchDriveLetter);
	strFileName += m_strFillFileName;
	strFileName += CString(chCount);
	strFileName += m_strFillFileExtName;

	ShowMsg(MakeFillingFileMsg(strFileName));
	
	fillFile.Open(strFileName, CFile::modeCreate | CFile::modeReadWrite);
	fillFile.SetLength(iFileLength);
	fillFile.Close();

	ShowMsg(MakeFillFileFinishMsg(strFileName));

	return;
}

void CFillDiskPublicDlg::CreateFillFileFAT32(wchar_t * wchDriveLetter, __int64 iFileLength)
{
	while(iFileLength > m_iFAT32FileMaxSize)
	{
		CreateFillFile(wchDriveLetter, m_iFAT32FileMaxSize);
		RefreshDiskInfo();

		iFileLength -= m_iFAT32FileMaxSize;
	}

	if (0 < iFileLength)
	{
		CreateFillFile(wchDriveLetter, iFileLength);
		RefreshDiskInfo();
		AfterOneDiskFillFinished(wchDriveLetter);
	}
}

void CFillDiskPublicDlg::RefreshDiskInfo(void)
{
	if (!m_bStartWithCmdArgs)
	{
		for (int i = 0; i < m_iFixedDriveCount; i++)
		{
			POSITION pos;
			pos = m_WchDiskLetterList.FindIndex(i);
			wchar_t * wchDriveLetter = m_WchDiskLetterList.GetAt(pos).AllocSysString();
			pos = m_nDiskIndexList.FindIndex(i);
			int iDiskIndex = m_nDiskIndexList.GetAt(pos);

			CListBox * pListBox = (CListBox * )GetDlgItem(IDC_LIST_DISK0 + iDiskIndex);
			SetListString(pListBox, wchDriveLetter);
		}
	}
	return;
}

void CFillDiskPublicDlg::DeleteAllFillFiles(void)
{
	for (int i = 0; i < m_iFixedDriveCount; i++)
	{
		POSITION pos = m_WchDiskLetterList.FindIndex(i);
		wchar_t * wchDriveLetter = m_WchDiskLetterList.GetAt(pos).AllocSysString();
		if (DRIVE_FIXED == GetDriveType(wchDriveLetter))
		{
			DeleteFillFiles(wchDriveLetter);	
		}
	}
	ShowMsg(CString("All filled files deleted."));
	if (m_bStartWithCmdArgs)
	{
		ShowFiveSecondsDelay();
	}
}

void CFillDiskPublicDlg::DeleteFillFiles(wchar_t * wchDriveLetter)
{
	CString strFileName = CString("");
	strFileName  = CString(wchDriveLetter);
	strFileName += m_strFillFileName;
	strFileName += CString("*");
	strFileName += m_strFillFileExtName;

	CFileFind finder;
	CFile fillFile;
	BOOL bFind = finder.FindFile(strFileName);
	while (bFind)
	{
		bFind = finder.FindNextFile();
		fillFile.Remove(finder.GetFilePath());
	}

	return;
}

CString CFillDiskPublicDlg::GetFillFileName(void)
{
	return m_strFillFileName;
}

void CFillDiskPublicDlg::SetFillFileName(CString strFillFileName)
{
	m_strFillFileName = strFillFileName;
}

CString CFillDiskPublicDlg::GetFillFileExtName(void)
{
	return m_strFillFileExtName;
}

void CFillDiskPublicDlg::SetFillFileExtName(CString strFillFileExtName)
{
	m_strFillFileExtName = strFillFileExtName;
}

__int64 CFillDiskPublicDlg::GetFileLength(void)
{
	return m_iFileLength;
}

void CFillDiskPublicDlg::SetFileLength(__int64 iFileLength)
{
	m_iFileLength = iFileLength;
}

__int64 CFillDiskPublicDlg::GetFAT32FileMaxSize(void)
{
	return m_iFAT32FileMaxSize;
}

void CFillDiskPublicDlg::SetFAT32FileMaxSize(__int64 iFAT32FileMaxSize)
{
	m_iFAT32FileMaxSize = iFAT32FileMaxSize;
}

wchar_t CFillDiskPublicDlg::GetCurrentDisk(void)
{
	return m_wchCurrentDisk;
}

void CFillDiskPublicDlg::SetCurrentDisk(wchar_t wchCurrentDisk)
{
	m_wchCurrentDisk = wchCurrentDisk;
}

int CFillDiskPublicDlg::GetFAT32DiskCount(void)
{
	return m_iFAT32DiskCount;
}

void CFillDiskPublicDlg::SetFAT32DiskCount(int iFAT32DiskCount)
{
	m_iFAT32DiskCount = iFAT32DiskCount;
}

int CFillDiskPublicDlg::GetAllDiskCount(void)
{
	return m_iAllDiskCount;
}

void CFillDiskPublicDlg::SetAllDiskCount(int iAllDiskCount)
{
	m_iAllDiskCount = iAllDiskCount;
}

HANDLE CFillDiskPublicDlg::GetOutPutCmdHandle(void)
{
	return m_hOutPut;
}

void CFillDiskPublicDlg::SetOutPutCmdHandle(HANDLE hOutPut)
{
	m_hOutPut = hOutPut;
}

CString CFillDiskPublicDlg::MakeFillDiskFinishMsg(wchar_t wchDriveLetter)
{
	CTime tm = CTime::GetCurrentTime();
	CString strMsg = tm.Format("%H:%M:%S");
	strMsg += CString(" Disk ") + CString(wchDriveLetter) + CString(" fill finished.");
	return strMsg;
}

CString CFillDiskPublicDlg::MakeFillingFileMsg(CString strCurrentFillFileName)
{
	CTime tm = CTime::GetCurrentTime();
	CString strMsg = tm.Format("%H:%M:%S");
	strMsg += CString(" Filling file ") + strCurrentFillFileName + CString(" ...");
	return strMsg;
}

CString CFillDiskPublicDlg::MakeFillFileFinishMsg(CString strCurrentFillFileName)
{
	CTime tm = CTime::GetCurrentTime();
	CString strMsg = tm.Format("%H:%M:%S");
	strMsg += CString(" Fill file ") + strCurrentFillFileName + CString(" finished.");
	return strMsg;
}

void CFillDiskPublicDlg::ShowMsg(CString strMsg)
{
	if (m_bStartWithCmdArgs)
	{
		strMsg += CString("\n");
		int iLength = strMsg.GetLength();
		WriteConsole(m_hOutPut, strMsg, iLength, NULL, NULL);
	}
	else
	{
		CListBox * listMsg = (CListBox *)GetDlgItem(IDC_LIST_MESSAGE);
		listMsg->AddString(strMsg);
	}
}

void CFillDiskPublicDlg::AfterAllDiskFillFinished()
{
	ShowMsg(CString("Fill all disks finished."));
	if (m_bStartWithCmdArgs)
	{
		ShowFiveSecondsDelay();
	}
	else
	{
		SetFillButtonStatus(TRUE);
	}
}

void CFillDiskPublicDlg::AfterOneDiskFillFinished(wchar_t * wchDriveLetter)
{
	ShowMsg(MakeFillDiskFinishMsg(wchDriveLetter[0]));
	ShowMsg(CString("Other disks still filling..."));
	ShowMsg(CString(" "));
}

void CFillDiskPublicDlg::ShowFiveSecondsDelay()
{
	ShowMsg(CString(" "));
	for (int i = 5; i >0; i--)
	{
		char chCount[65];
		_itoa_s(i, chCount, 65, 10);
		CString strMsg = CString("Filldisk will exit after ") + CString(chCount)
			+ CString(" seconds...");
		ShowMsg(strMsg);
		Sleep(1000);
	}
}

void CFillDiskPublicDlg::SetFillButtonStatus(BOOL bStatus)
{
	if (!m_bStartWithCmdArgs)
	{
		((CButton *)GetDlgItem(IDC_BUTTON_FILLDISK_APPLY))->EnableWindow(bStatus);
		((CButton *)GetDlgItem(IDCANCEL))->EnableWindow(bStatus);
		((CButton *)GetDlgItem(IDC_BUTTON_DELETEFILLFILE))->EnableWindow(bStatus);
	}
}

void CFillDiskPublicDlg::SetStartWithCmdArgs(bool bStartWithCmdArgs)
{
	m_bStartWithCmdArgs = bStartWithCmdArgs;
}

void CFillDiskPublicDlg::ShowHelpWindow()
{
	CString strMsg = CString("Help information:\n");
	strMsg += CString("Usage:\n");
	strMsg += CString("Filldisk.exe -help: Show this window.\n");
	strMsg += CString("Filldisk.exe -clean: Delete all dummy files from all fixed disks.\n");
	strMsg += CString("\n");
	strMsg += CString("You can fill all disks like this:\n");
	strMsg += CString("Example: Filldisk.exe -fill all 10\n");
	strMsg += CString("Result: All disks' free space = 10MB\n");
	strMsg += CString("\n");
	strMsg += CString("Also you can fill specifical disk(s) like this:\n");
	strMsg += CString("Example: Filldisk.exe -fill c e 5\n");
	strMsg += CString("Result: Disk C and E's free space = 5MB\n");
	strMsg += CString("\n");
	strMsg += CString("Note: -clean and -fill can NOT be used together.");
	AfxMessageBox(strMsg);
}

void CFillDiskPublicDlg::ShowErrorWindow()
{
	CString strMsg = CString("Error Args\n");
	strMsg += CString("Please type filldisk.exe -h to get help information.");
	AfxMessageBox(strMsg);
}

void CFillDiskPublicDlg::OnBnClickedButtonSendEMail()
{
	SendEMailToAuthor();
}

void CFillDiskPublicDlg::SendEMailToAuthor()
{
	ShellExecute(NULL, _T("open"), _T("mailto:") + m_strEMailAddress, 
		NULL, NULL, SW_SHOWMAXIMIZED);
}

void CFillDiskPublicDlg::ChangeDialogSize(void)
{
	CString strTest = CString("");

	CDC * cdcWindow = this->GetWindowDC();

	int iScreenWidth  = GetDeviceCaps(cdcWindow->m_hDC, HORZRES);
	int iScreenHeight = GetDeviceCaps(cdcWindow->m_hDC, VERTRES);

	ReleaseDC(cdcWindow);

	int iLargeWidth  = 1280, iLargeHeight  = 1024;	// 1280 * 1024 
	int iMiddleWidth = 1024, iMiddleHeight = 800;	// 1024 * 800 
	int iSmallWidth  = 800,  iSmallHeight  = 600; 	// 800 * 600 
	int iMinWidth    = 640,  iMinHeight    = 480; 	// 640 * 480 

	// Screen resolution higher than 1280 * 1024: No changes.
	if ((iScreenWidth >= iLargeWidth) && (iScreenHeight >= iLargeHeight))
	{
		return;
	}

	// Screen resolution between 1280 * 1024 and 1024 * 800: Change to 0.8
	if ((iScreenWidth >= iMiddleWidth) && (iScreenHeight >= iMiddleHeight))
	{
		SetDialogSize(0.8);
		return;
	}

	// Screen resolution between 1024 * 800 and 800 * 600: Change to 0.6
	if ((iScreenWidth >= iSmallWidth) && (iScreenHeight >= iSmallHeight))
	{
		SetDialogSize(0.6);
		return;
	}

	// Screen resolution lower than 800 * 600: Change to 0.5
	//if ((iScreenWidth >= iMinWidth) && (iScreenHeight >= iMinHeight))
	{
		SetDialogSize(0.5);
		return;
	}
}

void CFillDiskPublicDlg::SetDialogSize(double scale)
{
	CList<int, int> nCtrlIDList;
	
	// Find all controls
	CWnd * pCtrlWnd = GetWindow(GW_CHILD);
	CString strCtrlName;
	while (pCtrlWnd != NULL)
	{
		int iCtrlID  = pCtrlWnd->GetDlgCtrlID();
		// Change the controls which ID is higher than 1000 ( IDC_LIST_MESSAGE )
		if (iCtrlID >= IDC_LIST_MESSAGE)
		{
			nCtrlIDList.AddTail(iCtrlID);
		}
		pCtrlWnd = pCtrlWnd->GetNextWindow(GW_HWNDNEXT);
	}

	// OK and CANCEL button 
	// No OK button on this dialog.
	//nCtrlIDList.AddTail(IDOK);
	nCtrlIDList.AddTail(IDCANCEL);

	// Change font.
	CFont * ctrlFont;
	ctrlFont = this->GetFont();
	ctrlFont->GetLogFont(&m_lf);
	m_lf.lfHeight = (int)(m_lf.lfHeight * scale);
	m_font.CreateFontIndirect(&m_lf);

	CRect ctrlRect;
	int iWidth, iHeight;
	for (int i = 0; i < nCtrlIDList.GetCount(); i++)
	{
		int iCtrlID = nCtrlIDList.GetAt(nCtrlIDList.FindIndex(i));
			
		pCtrlWnd = GetDlgItem(iCtrlID);
		pCtrlWnd->GetWindowRect(&ctrlRect);
		ScreenToClient(ctrlRect);

		iWidth  = ctrlRect.right - ctrlRect.left;
		iHeight = ctrlRect.bottom - ctrlRect.top;
		iWidth  = (int)(iWidth * scale);
		// Don't change the height of the CList which displays disk info.
		if ((iCtrlID < IDC_LIST_DISK0) || (IDC_LIST_DISK25 < iCtrlID ))
		{
			iHeight = (int)(iHeight * scale);
		}

		int iLeft = 0, iTop = 0;
		iLeft	= (int)(ctrlRect.left * scale);
		if (( iCtrlID < IDC_LIST_DISK0  ) || (IDC_LIST_DISK25 < iCtrlID  )
		 || ( iCtrlID < IDC_CHECK_DISK0 ) || (IDC_CHECK_DISK25 < iCtrlID ))
		{
			iTop	= (int)(ctrlRect.top * scale);
		}

		pCtrlWnd->SetWindowPos(NULL, iLeft, iTop, iWidth, iHeight, SWP_SHOWWINDOW);
		pCtrlWnd->SetFont(&m_font);
	}

	// Change the dialog size.
	this->GetWindowRect(&ctrlRect);
	ScreenToClient(ctrlRect);
	iWidth  = ctrlRect.right - ctrlRect.left;
	iHeight = ctrlRect.bottom - ctrlRect.top;
	iWidth  = (int)(iWidth  * scale);
	iHeight = (int)(iHeight * scale);
	this->SetWindowPos(NULL, 10, 10, iWidth, iHeight, SWP_SHOWWINDOW);
	this->SetFont(&m_font);
}

